﻿using System;
using System.Collections.Generic;
using IWMAG.Core.EnhancedProperties.PropertyNodes;

namespace IWMAG.Core.EnhancedProperties
{
    public abstract class PropertyBacker
    {
        protected internal PropertyBacker() { }
        public string PropertyName { get; set; }
        public IPropertyMetadata Metadata { get; set; }

        internal abstract void DisposeObjectReferences(UniqueIdentifier objectID);
    }
    
    public sealed class PropertyBacker<T> : PropertyBacker
    {
        private DefaultValueNode<T> defaultValueNode;
        internal DefaultValueNode<T> DefaultValue
        {
            get
            {
                return defaultValueNode;
            }
        }

        internal PropertyBacker(T defaultValue = default(T), Func<T, T> coerceValueCallback = null)
        {
            defaultValueNode = new DefaultValueNode<T>(defaultValue);
            backingDict = new Dictionary<UniqueIdentifier, PropertyNodeList<T>>();
            if (coerceValueCallback == null)
            {
                this.coerceValueCB = i => i;
            }
            else
            {
                this.coerceValueCB = coerceValueCallback;
            }

            _uniqueID = UniqueIdentifier.CreateNew();
        }

        private Func<T, T> coerceValueCB;
        internal Func<T, T> CoerceValueCallback
        {
            get
            {
                return coerceValueCB;
            }
        }

        private readonly UniqueIdentifier _uniqueID;
        internal UniqueIdentifier UniqueID { 
            get
        {
            return _uniqueID;
        }
        }

        private Dictionary<UniqueIdentifier, PropertyNodeList<T>> backingDict;
        internal Dictionary<UniqueIdentifier, PropertyNodeList<T>> BackingDictionary
        {
            get
            {
                return backingDict;
            }
        }

        internal override void DisposeObjectReferences(UniqueIdentifier objectID)
        {
            PropertyNodeList<T> pnl;
            if (backingDict.TryGetValue(objectID,out pnl))
            {
                pnl.Dispose();
                backingDict.Remove(objectID);
            }

            pnl = null;
        }

        internal void PropertyNodeListRequestsDeletion(UniqueIdentifier associatedObjectId)
        {

            var c = GetOrCreatePropertyNodeList(associatedObjectId);
            backingDict.Remove(associatedObjectId);
            c.Dispose();
            c = null;
        }

        internal PropertyNodeList<T> GetOrCreatePropertyNodeList(IPropertyContainer container)
        {

            return GetOrCreatePropertyNodeList(container.UniqueID);
        }

        internal PropertyNodeList<T> GetOrCreatePropertyNodeList(UniqueIdentifier id)
        {
            PropertyNodeList<T> t;
            if (BackingDictionary.TryGetValue(id, out t))
            {
            }
            else
            {
                t = new PropertyNodeList<T>(DefaultValue, CoerceValueCallback, id, this);
                BackingDictionary[id] = t;
            }

            return t;
        }
    }
}
